package com.huilian.iotbox.client.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.huilian.iotbox.client.dao.MerchantStoreDao;
import com.huilian.iotbox.client.service.*;
import com.huilian.iotbox.data.common.RedisKey;
import com.huilian.iotbox.data.common.ServerResponse;
import com.huilian.iotbox.data.dto.*;
import com.huilian.iotbox.data.enums.*;
import com.huilian.iotbox.data.exception.SysException;
import com.huilian.iotbox.data.po.MerchantStore;
import com.huilian.iotbox.data.po.SystemRiskConfig;
import com.huilian.iotbox.data.utils.DateTimeUtils;
import com.huilian.iotbox.data.utils.SciCalUtils;
import com.huilian.iotbox.data.vo.MerchantStoreVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author 谢洛涛
 * @date 2021/1/18 19:04
 */
@Service
@Slf4j
public class MerchantStoreServiceImpl implements MerchantStoreService {
    @Resource
    private MerchantStoreDao merchantStoreDao;
    @Autowired
    private SystemRiskConfigService systemRiskConfigService;
    @Autowired
    private RedisTemplate<String, Serializable> redisCacheTemplate;

    @Override
    public MerchantStore findMerchantStore(MerchantStore merchantStore) {
        if (StringUtils.isEmpty(merchantStore.getId())) {
            throw new RuntimeException("缺少场地ID");
        }
        return merchantStoreDao.findMerchantStore(merchantStore);
    }


    @Override
    public MerchantStore findStore(MerchantStoreDto merchantStoreDto) {
        return merchantStoreDao.findStore(merchantStoreDto);
    }

    /**
     * 设置用户的支付限制
     */
    @Override
    public void setMemberRisk(Long memberId, Integer merchantStoreId, Date gmtPayment, BigDecimal money) {
        // 分钟,小时,天数,各存一个,
        // 参数1=memberId,参数2=merchant_store_id,参数3= 分钟:1 || 小时:2 || 天数:3
        String minuteTime = DateTimeUtils.formatByPattern(gmtPayment, "yyyyMMddHHmm");
        String hourTime = DateTimeUtils.formatByPattern(gmtPayment, "yyyyMMddHH");
        String dayTime = DateTimeUtils.formatByPattern(gmtPayment, "yyyyMMdd");

        String minuteKey = String.format(RedisKey.MEMBER_RISK_KEY, memberId, SystemRiskConfigTypeEnum.MINUTE.getCode(), minuteTime);
        String hourKey = String.format(RedisKey.MEMBER_RISK_KEY, memberId, SystemRiskConfigTypeEnum.HOUR.getCode(), hourTime);
        String dayKey = String.format(RedisKey.MEMBER_RISK_KEY, memberId, SystemRiskConfigTypeEnum.DAY.getCode(), dayTime);

        JSONObject minuteJson = (JSONObject) redisCacheTemplate.opsForValue().get(minuteKey);
        JSONObject hourJson = (JSONObject) redisCacheTemplate.opsForValue().get(hourKey);
        JSONObject dayJson = (JSONObject) redisCacheTemplate.opsForValue().get(dayKey);

        this.setMemberRiskRedis(minuteJson, minuteKey, SystemRiskConfigTypeEnum.MINUTE.getCode(), "member", gmtPayment, money);
        this.setMemberRiskRedis(hourJson, hourKey, SystemRiskConfigTypeEnum.HOUR.getCode(), "member", gmtPayment, money);
        this.setMemberRiskRedis(dayJson, dayKey, SystemRiskConfigTypeEnum.DAY.getCode(), "member", gmtPayment, money);

        // 参数1=merchant_store_id,参数2= 分钟:1 || 小时:2 || 天数:3
        String merchantStoreDayKey = String.format(RedisKey.MEMBER_RISK_MERCHANT_STORE_KEY, merchantStoreId, SystemRiskConfigTypeEnum.DAY.getCode(), dayTime);

        JSONObject merchantStoreDayJson = (JSONObject) redisCacheTemplate.opsForValue().get(merchantStoreDayKey);
        // 计算门店总限额
        this.setMemberRiskRedis(merchantStoreDayJson, merchantStoreDayKey, SystemRiskConfigTypeEnum.DAY.getCode(), "merchant_store", gmtPayment, money);
    }

    /**
     * 设置存入缓存的参数
     * jsonObject: 存入的参数
     * key: 缓存Key
     * type: 分钟 = 1 , 小时 = 2 , 天数 = 3
     * redisType: 是用户还是场地 member = 'member',merchant_store = 'merchant_store'
     * gmtPayment: 支付时间
     * money: 订单支付金额
     */
    public void setMemberRiskRedis(JSONObject jsonObject, String key, Integer type, String redisType, Date gmtPayment, BigDecimal money) {

        TimeUnit timeUnit = TimeUnit.DAYS;
        //指定获取需要获取的时间点
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(gmtPayment);
        // 将时分秒,毫秒域清零
        if (type.equals(SystemRiskConfigTypeEnum.MINUTE.getCode())) {
            calendar.set(Calendar.SECOND, 0);
            timeUnit = TimeUnit.MINUTES;
        } else if (type.equals(SystemRiskConfigTypeEnum.HOUR.getCode())) {
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            timeUnit = TimeUnit.HOURS;
        } else if (type.equals(SystemRiskConfigTypeEnum.DAY.getCode())) {
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            timeUnit = TimeUnit.DAYS;
        }
        if (ObjectUtils.isEmpty(jsonObject)) {
            jsonObject = new JSONObject();
            jsonObject.put("gmtPayment", calendar.getTime().getTime());
            if (redisType.equals("member")) {
                jsonObject.put("count", 1);
            }
            jsonObject.put("money", money);
        } else {
            if (redisType.equals("member")) {
                jsonObject.put("count", jsonObject.getInteger("count") + 1);
            }
            jsonObject.put("money", SciCalUtils.sciCalToBD(jsonObject.getBigDecimal("money").add(money), 2));
        }
        redisCacheTemplate.opsForValue().set(key, jsonObject, 1, timeUnit);
    }

    @Override
    public void getMemberRisk(Long memberId, Integer merchantStoreId) {
        log.info("memberId：" + memberId);
        log.info("merchantStoreId：" + merchantStoreId);
        MerchantStoreDto merchantStoreDto = new MerchantStoreDto();
        merchantStoreDto.setId(merchantStoreId);
        MerchantStore merchantStore = this.findStore(merchantStoreDto);
        // 参数1=memberId,参数2=merchant_store_id,参数3= 分钟:1 || 小时:2 || 天数:3
        String minuteTime = DateTimeUtils.formatByPattern(new Date(), "yyyyMMddHHmm");
        String hourTime = DateTimeUtils.formatByPattern(new Date(), "yyyyMMddHH");
        String dayTime = DateTimeUtils.formatByPattern(new Date(), "yyyyMMdd");

        String minuteKey = String.format(RedisKey.MEMBER_RISK_KEY, memberId, SystemRiskConfigTypeEnum.MINUTE.getCode(), minuteTime);
        String hourKey = String.format(RedisKey.MEMBER_RISK_KEY, memberId, SystemRiskConfigTypeEnum.HOUR.getCode(), hourTime);
        String dayKey = String.format(RedisKey.MEMBER_RISK_KEY, memberId, SystemRiskConfigTypeEnum.DAY.getCode(), dayTime);

        // 会员每分钟限额
        BigDecimal memberMinuteQuota = BigDecimal.ZERO;
        // 会员每分钟限制笔数
        Integer memberMinutePayCount = 0;
        SystemRiskConfig systemRiskConfig = new SystemRiskConfig();
        // 判断场地有设置限额就用场地的,如果没有就用平台的
        if (ObjectUtils.isEmpty(merchantStore.getMemberMinuteQuota()) || ObjectUtils.isEmpty(merchantStore.getMemberMinutePayCount())) {
            systemRiskConfig = systemRiskConfigService.findSystemRiskConfigByType(SystemRiskConfigTypeEnum.MINUTE.getCode());
        }
        if (ObjectUtils.isEmpty(merchantStore.getMemberMinuteQuota())) {
            if (!ObjectUtils.isEmpty(systemRiskConfig) && !ObjectUtils.isEmpty(systemRiskConfig.getMoney())) {
                memberMinuteQuota = systemRiskConfig.getMoney();
            }
        } else {
            memberMinuteQuota = merchantStore.getMemberMinuteQuota();
        }
        if (ObjectUtils.isEmpty(merchantStore.getMemberMinutePayCount())) {
            if (!ObjectUtils.isEmpty(systemRiskConfig) && !ObjectUtils.isEmpty(systemRiskConfig.getCount())) {
                memberMinutePayCount = systemRiskConfig.getCount();
            }
        } else {
            memberMinutePayCount = merchantStore.getMemberMinutePayCount();
        }
        JSONObject minuteJson = (JSONObject) redisCacheTemplate.opsForValue().get(minuteKey);
        if (!ObjectUtils.isEmpty(minuteJson)) {
            log.info("每分钟限额: {}", memberMinuteQuota);
            log.info("每分钟限笔数: {}", memberMinutePayCount);
            log.info("每分钟-门店信息: {}", JSON.toJSONString(merchantStore));
            if (minuteJson.getInteger("count") >= memberMinutePayCount && minuteJson.getBigDecimal("money").compareTo(memberMinuteQuota) >= 0) {
                log.error("超出每分钟限额，支付金额笔数信息: {}", minuteJson);
                throw new SysException("支付频繁");
            }
        }


        // 会员每小时限额
        BigDecimal memberHourQuota = BigDecimal.ZERO;
        // 会员每小时限制笔数
        Integer memberHourPayCount = 0;
        systemRiskConfig = new SystemRiskConfig();
        // 判断场地有设置限额就用场地的,如果没有就用平台的
        if (ObjectUtils.isEmpty(merchantStore.getMemberHourQuota()) || ObjectUtils.isEmpty(merchantStore.getMemberHourPayCount())) {
            systemRiskConfig = systemRiskConfigService.findSystemRiskConfigByType(SystemRiskConfigTypeEnum.HOUR.getCode());
        }
        if (ObjectUtils.isEmpty(merchantStore.getMemberHourQuota())) {
            if (!ObjectUtils.isEmpty(systemRiskConfig) && !ObjectUtils.isEmpty(systemRiskConfig.getMoney())) {
                memberHourQuota = systemRiskConfig.getMoney();
            }
        } else {
            memberHourQuota = merchantStore.getMemberHourQuota();
        }
        if (ObjectUtils.isEmpty(merchantStore.getMemberHourPayCount())) {
            if (!ObjectUtils.isEmpty(systemRiskConfig) && !ObjectUtils.isEmpty(systemRiskConfig.getCount())) {
                memberHourPayCount = systemRiskConfig.getCount();
            }
        } else {
            memberHourPayCount = merchantStore.getMemberHourPayCount();
        }
        JSONObject hourJson = (JSONObject) redisCacheTemplate.opsForValue().get(hourKey);
        if (!ObjectUtils.isEmpty(hourJson)) {
            log.info("每小时限额: {}", memberHourQuota);
            log.info("每小时限笔数: {}", memberHourPayCount);
            log.info("每小时-门店信息: {}", JSON.toJSONString(merchantStore));
            if (hourJson.getInteger("count") >= memberHourPayCount && hourJson.getBigDecimal("money").compareTo(memberHourQuota) >= 0) {
                log.error("超出每小时限额，支付金额笔数信息: {}", hourJson);
                throw new SysException("支付频繁");
            }
        }


        // 会员每天限额
        BigDecimal memberDayQuota = BigDecimal.ZERO;
        // 会员每天限制笔数
        Integer memberDayPayCount = 0;
        systemRiskConfig = new SystemRiskConfig();
        // 判断场地有设置限额就用场地的,如果没有就用平台的
        if (ObjectUtils.isEmpty(merchantStore.getMemberDayQuota()) || ObjectUtils.isEmpty(merchantStore.getMemberDayPayCount())) {
            systemRiskConfig = systemRiskConfigService.findSystemRiskConfigByType(SystemRiskConfigTypeEnum.DAY.getCode());
        }
        if (ObjectUtils.isEmpty(merchantStore.getMemberDayQuota())) {
            if (!ObjectUtils.isEmpty(systemRiskConfig) && !ObjectUtils.isEmpty(systemRiskConfig.getMoney())) {
                memberDayQuota = systemRiskConfig.getMoney();
            }
        } else {
            memberDayQuota = merchantStore.getMemberDayQuota();
        }
        if (ObjectUtils.isEmpty(merchantStore.getMemberDayPayCount())) {
            if (!ObjectUtils.isEmpty(systemRiskConfig) && !ObjectUtils.isEmpty(systemRiskConfig.getCount())) {
                memberDayPayCount = systemRiskConfig.getCount();
            }
        } else {
            memberDayPayCount = merchantStore.getMemberDayPayCount();
        }

        JSONObject dayJson = (JSONObject) redisCacheTemplate.opsForValue().get(dayKey);
        if (!ObjectUtils.isEmpty(dayJson)) {
            log.info("每天限额: {}", memberDayQuota);
            log.info("每天限笔数: {}", memberDayPayCount);
            log.info("每天-门店信息: {}", JSON.toJSONString(merchantStore));
            if (dayJson.getInteger("count") >= memberDayPayCount && dayJson.getBigDecimal("money").compareTo(memberDayQuota) >= 0) {
                log.error("超出每天限额，支付金额笔数信息: {}", dayJson);
                throw new SysException("已超过当天限额，请明天再尝试");
            }
        }

        // 参数1=merchant_store_id,参数2= 分钟:1 || 小时:2 || 天数:3
        String merchantStoreDayKey = String.format(RedisKey.MEMBER_RISK_MERCHANT_STORE_KEY, merchantStoreId, SystemRiskConfigTypeEnum.DAY.getCode(), dayTime);
        // 门店每天限额
        if (!ObjectUtils.isEmpty(merchantStore.getDayQuota())) {
            log.info("场地-每天限额: {}", merchantStore.getDayQuota());
            log.info("场地信息: {}", JSON.toJSONString(merchantStore));
            JSONObject merchantStoreDayJson = (JSONObject) redisCacheTemplate.opsForValue().get(merchantStoreDayKey);
            if (!ObjectUtils.isEmpty(merchantStoreDayJson)) {
                if (merchantStoreDayJson.getBigDecimal("money").compareTo(merchantStore.getDayQuota()) >= 0) {
                    log.error("场地超出每天限额，支付金额笔数信息: {}", merchantStoreDayJson);
                    throw new SysException("当前场地已超过当天限额");
                }
            }
        }
    }


    @Override
    public MerchantStore findMerchantStoreById(Integer id) {
        return merchantStoreDao.findMerchantStoreById(id);
    }

    @Override
    public ServerResponse findRecentlyMerchantStoreByMember(MerchantStoreDto merchantStoreDto) {
        merchantStoreDto.setState(TermOfValidityCoinStateEnum.NORMAL.getCode());
        List<MerchantStoreVo> merchantStoreList = merchantStoreDao.findRecentlyMerchantStoreByMember(merchantStoreDto);
        return ServerResponse.createBySuccess(merchantStoreList);
    }
}


